home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tcl8.0 / mac / tclMacExit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  8.4 KB  |  317 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tclMacExit.c --
  3.  *
  4.  *    This file contains routines that deal with cleaning up various state
  5.  *    when Tcl/Tk applications quit.  Unfortunantly, not all state is cleaned
  6.  *    up by the process when an application quites or crashes.  Also you
  7.  *    need to do different things depending on wether you are running as
  8.  *    68k code, PowerPC, or a code resource.  The Exit handler code was 
  9.  *    adapted from code posted on alt.sources.mac by Dave Nebinger.
  10.  *
  11.  * Copyright (c) 1995 Dave Nebinger.
  12.  * Copyright (c) 1995-1996 Sun Microsystems, Inc.
  13.  *
  14.  * See the file "license.terms" for information on usage and redistribution
  15.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  16.  *
  17.  * SCCS: @(#) tclMacExit.c 1.4 96/12/12 15:45:07
  18.  */
  19.  
  20. #include "tclInt.h"
  21. #include "tclMacInt.h"
  22. #include <SegLoad.h>
  23. #include <Traps.h>
  24.  
  25. /*
  26.  * Various typedefs and defines needed to patch ExitToShell.
  27.  */
  28.  
  29. enum {
  30.         uppExitToShellProcInfo = kPascalStackBased
  31. };
  32.  
  33. #if USESROUTINEDESCRIPTORS
  34. typedef UniversalProcPtr ExitToShellUPP;
  35.  
  36. #define CallExitToShellProc(userRoutine)        \
  37.         CallUniversalProc((UniversalProcPtr)(userRoutine),uppExitToShellProcInfo)
  38. #define NewExitToShellProc(userRoutine) \
  39.         (ExitToShellUPP)NewRoutineDescriptor((ProcPtr)(userRoutine), \
  40.         uppExitToShellProcInfo, GetCurrentArchitecture())
  41.  
  42. #else
  43. typedef ExitToShellProcPtr ExitToShellUPP;
  44.  
  45. #define CallExitToShellProc(userRoutine)        \
  46.         (*(userRoutine))()
  47. #define NewExitToShellProc(userRoutine) \
  48.         (ExitToShellUPP)(userRoutine)
  49. #endif
  50.  
  51. #define DisposeExitToShellProc(userRoutine) \
  52.         DisposeRoutineDescriptor(userRoutine)
  53.  
  54. #if defined(powerc)||defined(__powerc)
  55. #pragma options align=mac68k
  56. #endif
  57. struct ExitToShellUPPList{
  58.         struct ExitToShellUPPList* nextProc;
  59.         ExitToShellUPP userProc;
  60. };
  61. #if defined(powerc)||defined(__powerc)
  62. #pragma options align=reset
  63. #endif
  64.  
  65. typedef struct ExitToShellDataStruct ExitToShellDataRec,* ExitToShellDataPtr,** ExitToShellDataHdl;
  66.  
  67. typedef struct ExitToShellUPPList ExitToShellUPPList,* ExitToShellUPPListPtr,** ExitToShellUPPHdl;
  68.  
  69. #if defined(powerc)||defined(__powerc)
  70. #pragma options align=mac68k
  71. #endif
  72. struct ExitToShellDataStruct{
  73.     unsigned long a5;
  74.     ExitToShellUPPList* userProcs;
  75.     ExitToShellUPP oldProc;
  76. };
  77. #if defined(powerc)||defined(__powerc)
  78. #pragma options align=reset
  79. #endif
  80.  
  81. /*
  82.  * Static globals used within this file.
  83.  */
  84. static ExitToShellDataPtr gExitToShellData = (ExitToShellDataPtr) NULL;
  85.  
  86.  
  87. /*
  88.  *----------------------------------------------------------------------
  89.  *
  90.  * TclPlatformExit --
  91.  *
  92.  *    This procedure implements the Macintosh specific exit routine.
  93.  *    We explicitly callthe ExitHandler function to do various clean
  94.  *    up.  
  95.  *
  96.  * Results:
  97.  *    None.
  98.  *
  99.  * Side effects:
  100.  *    We exit the process.
  101.  *
  102.  *----------------------------------------------------------------------
  103.  */
  104.  
  105. void
  106. TclPlatformExit(
  107.     int status)        /* Ignored. */
  108. {
  109.     TclMacExitHandler();
  110.     ExitToShell();
  111. }
  112.  
  113. /*
  114.  *----------------------------------------------------------------------
  115.  *
  116.  * TclMacExitHandler --
  117.  *
  118.  *    This procedure is invoked after Tcl at the last possible moment
  119.  *    to clean up any state Tcl has left around that may cause other
  120.  *    applications to crash.  For example, this function can be used
  121.  *    as the termination routine for CFM applications.
  122.  *
  123.  * Results:
  124.  *    None.
  125.  *
  126.  * Side effects:
  127.  *    Various cleanup occurs.
  128.  *
  129.  *----------------------------------------------------------------------
  130.  */
  131.  
  132. void
  133. TclMacExitHandler()
  134. {
  135.     ExitToShellUPPListPtr curProc;
  136.  
  137.     /*
  138.      * Loop through all installed Exit handlers
  139.      * and call them.  Always make sure we are in
  140.      * a clean state in case we are recursivly called.
  141.      */
  142.     if ((gExitToShellData) != NULL && (gExitToShellData->userProcs != NULL)){
  143.     
  144.     /*
  145.      * Call the installed exit to shell routines.
  146.      */
  147.     curProc = gExitToShellData->userProcs;
  148.     do {
  149.         gExitToShellData->userProcs = curProc->nextProc;
  150.         CallExitToShellProc(curProc->userProc);
  151.         DisposeExitToShellProc(curProc->userProc);
  152.         DisposePtr((Ptr) curProc);
  153.         curProc = gExitToShellData->userProcs;
  154.     } while (curProc != (ExitToShellUPPListPtr) NULL);
  155.     }
  156.  
  157.     return;
  158. }
  159.  
  160. /*
  161.  *----------------------------------------------------------------------
  162.  *
  163.  * TclMacInstallExitToShellPatch --
  164.  *
  165.  *    This procedure installs a way to clean up state at the latest
  166.  *    possible moment before we exit.  These are things that must
  167.  *    be cleaned up or the system will crash.  The exact way in which
  168.  *    this is implemented depends on the architecture in which we are
  169.  *    running.  For 68k applications we patch the ExitToShell call.
  170.  *    For PowerPC applications we just create a list of procs to call.
  171.  *    The function ExitHandler should be installed in the Code 
  172.  *    Fragments terminiation routine.
  173.  *
  174.  * Results:
  175.  *    None.
  176.  *
  177.  * Side effects:
  178.  *    Installs the new routine.
  179.  *
  180.  *----------------------------------------------------------------------
  181.  */
  182.  
  183. OSErr 
  184. TclMacInstallExitToShellPatch(
  185.     ExitToShellProcPtr newProc)        /* Function pointer. */
  186. {
  187.     ExitToShellUPP exitHandler;
  188.     ExitToShellUPPListPtr listPtr;
  189.  
  190.     if (gExitToShellData == (ExitToShellDataPtr) NULL){
  191.     TclMacInitExitToShell(true);
  192.     }
  193.  
  194.     /*
  195.      * Add the passed in function pointer to the list of functions
  196.      * to be called when ExitToShell is called.
  197.      */
  198.     exitHandler = NewExitToShellProc(newProc);
  199.     listPtr = (ExitToShellUPPListPtr) NewPtrClear(sizeof(ExitToShellUPPList));
  200.     listPtr->userProc = exitHandler;
  201.     listPtr->nextProc = gExitToShellData->userProcs;
  202.     gExitToShellData->userProcs = listPtr;
  203.  
  204.     return noErr;
  205. }
  206.  
  207. /*
  208.  *----------------------------------------------------------------------
  209.  *
  210.  * ExitToShellPatchRoutine --
  211.  *
  212.  *    This procedure is invoked when someone calls ExitToShell for
  213.  *    this application.  This function performs some last miniute
  214.  *    clean up and then calls the real ExitToShell routine.
  215.  *
  216.  * Results:
  217.  *    None.
  218.  *
  219.  * Side effects:
  220.  *    Various cleanup occurs.
  221.  *
  222.  *----------------------------------------------------------------------
  223.  */
  224.  
  225. static pascal void
  226. ExitToShellPatchRoutine()
  227. {
  228.     ExitToShellUPP oldETS;
  229.     long oldA5;
  230.  
  231.     /*
  232.      * Set up our A5 world.  This allows us to have
  233.      * access to our global variables in the 68k world.
  234.      */
  235.     oldA5 = SetCurrentA5();
  236.     SetA5(gExitToShellData->a5);
  237.  
  238.     /*
  239.      * Call the function that invokes all
  240.      * of the handlers.
  241.      */
  242.     TclMacExitHandler();
  243.  
  244.     /*
  245.      * Call the origional ExitToShell routine.
  246.      */
  247.     oldETS = gExitToShellData->oldProc;
  248.     DisposePtr((Ptr) gExitToShellData);
  249.     SetA5(oldA5);
  250.     CallExitToShellProc(oldETS);
  251.     return;
  252. }
  253.  
  254. /*
  255.  *----------------------------------------------------------------------
  256.  *
  257.  * TclMacInitExitToShell --
  258.  *
  259.  *    This procedure initializes the ExitToShell clean up machanism.
  260.  *    Generally, this is handled automatically when users make a call
  261.  *    to InstallExitToShellPatch.  However, it can be called 
  262.  *    explicitly at startup time to turn off the patching mechanism.
  263.  *    This can be used by code resources which could be removed from
  264.  *    the application before ExitToShell is called.
  265.  *
  266.  *    Note, if we are running from CFM code we never install the
  267.  *    patch.  Instead, the function ExitHandler should be installed
  268.  *    as the terminiation routine for the code fragment.
  269.  *
  270.  * Results:
  271.  *    None.
  272.  *
  273.  * Side effects:
  274.  *    Creates global state.
  275.  *
  276.  *----------------------------------------------------------------------
  277.  */
  278.  
  279. void 
  280. TclMacInitExitToShell(
  281.     int usePatch)    /* True if on 68k. */
  282. {
  283.     if (gExitToShellData == (ExitToShellDataPtr) NULL){
  284. #if GENERATINGCFM
  285.     gExitToShellData = (ExitToShellDataPtr)
  286.       NewPtr(sizeof(ExitToShellDataRec));
  287.     gExitToShellData->a5 = SetCurrentA5();
  288.     gExitToShellData->userProcs = (ExitToShellUPPList*) NULL;
  289. #else
  290.     ExitToShellUPP oldExitToShell, newExitToShellPatch;
  291.     short exitToShellTrap;
  292.     
  293.     /*
  294.      * Initialize patch mechanism.
  295.      */
  296.      
  297.     gExitToShellData = (ExitToShellDataPtr) NewPtr(sizeof(ExitToShellDataRec));
  298.     gExitToShellData->a5 = SetCurrentA5();
  299.     gExitToShellData->userProcs = (ExitToShellUPPList*) NULL;
  300.  
  301.     /*
  302.      * Save state needed to call origional ExitToShell routine.  Install
  303.      * the new ExitToShell code in it's place.
  304.      */
  305.     if (usePatch) {
  306.         exitToShellTrap = _ExitToShell & 0x3ff;
  307.         newExitToShellPatch = NewExitToShellProc(ExitToShellPatchRoutine);
  308.         oldExitToShell = (ExitToShellUPP)
  309.           NGetTrapAddress(exitToShellTrap, ToolTrap);
  310.         NSetTrapAddress((UniversalProcPtr) newExitToShellPatch,
  311.             exitToShellTrap, ToolTrap);
  312.         gExitToShellData->oldProc = oldExitToShell;
  313.     }
  314. #endif
  315.     }
  316. }
  317.